import { Inject, Injectable } from '@nestjs/common';
import * as dayjs from 'dayjs';
import * as fs from 'fs';
import * as path from 'path';
import { RedisService } from 'src/libs/redis/redis.service';
import { PrismaService } from 'src/libs/prisma/prisma.service';
import { LogService } from 'src/libs/log/log.service';
import { OpenaiService } from 'src/libs/openai/openai.service';
import { ConfigService } from '../config/config.service';
import { AnalysisJson } from 'src/prompt/analysis';
import { MatchData } from 'src/utils/init-data';
import { DataService } from '../data/data.service';
import getAiRecommendPrompt, { AIBettings, PredictionMap, StatusPredictionMap } from 'src/prompt/Ai-Recommend';
import { executeBatches } from 'src/utils';

@Injectable()
export class RecommendService {
  @Inject(RedisService)
  private readonly redisService: RedisService;
  @Inject(PrismaService)
  private readonly prismaService: PrismaService;
  @Inject(LogService)
  private readonly logService: LogService;
  @Inject(OpenaiService)
  private readonly openaiService: OpenaiService;
  @Inject(ConfigService)
  private readonly configService: ConfigService;
  @Inject(DataService)
  private readonly dataService: DataService;

  onModuleInit() {
    // this.aiTestAnalyz('Qwen');
    // this.aiTestAnalyz('DeepSeek');
    // this.aiTestAnalyz('Doubao');2
    // this.getAIBetPlanMatchResult('Qwen');
    // this.getAIBetPlanMatchResult('DeepSeek');
    // this.getAIBetPlanMatchResult('Doubao');
  }

  // 1) AI 分析推荐
  async aiBetAnalyz(aiModel: 'DeepSeek' | 'Doubao' | 'Qwen', date: Date[], collection?: boolean) {
    // 1 获取基础数据
    const CACHE_KEY = `AI_BET_PLAN:${aiModel}`;
    const saveDay = dayjs(date[0]).format('YYYY-MM-DD');
    const cacheHistoryBets = await this.redisService.lrange(CACHE_KEY, 0, -1);
    const historyBets = cacheHistoryBets.map((item) => JSON.parse(item));
    const matches = await this.prismaService.match.findMany({
      where: { matchTime: { gte: date[0], lte: date[1] } },
      include: { MatchAnalysis: true },
    });
    if (!matches.length) {
      return this.redisService.lpush(CACHE_KEY, JSON.stringify({ date: dayjs().format('YYYY-MM-DD'), profit: 0, bets: [] }));
    }
    if (historyBets.find((item) => item.date === saveDay && item.bets.length)) return;

    // 2 获取比赛分析数据(最多50条数据)
    const matchInfo = matches
      .slice(0, 40)
      .filter((item) => {
        const analysis = item.MatchAnalysis?.[0]?.analysisData;
        if (!analysis) return false;
        const analysisData = JSON.parse(analysis as string) as AnalysisJson;
        // 只选择评分 >= 7 的比赛
        return +analysisData.rating >= 7;
      })
      .map((item) => {
        const matchData = (JSON.parse(item.matchData as string) as MatchData) || {};
        return {
          matchId: item.matchId,
          homeTeam: matchData.homeTeam,
          awayTeam: matchData.awayTeam,
          matchTime: matchData.matchTime,
          leagueName: matchData.leagueName,
          matchNum: matchData.matchNum,
          matchAnalysis: JSON.parse((item.MatchAnalysis?.[0]?.analysisData || '{}') as string) as AnalysisJson,
          oddsHistory: [],
          // 新增：历史数据字段
          historyData: null as any,
          rankingData: null as any,
        };
      });

    // 3 获取每场比赛的详细数据（历史数据、赔率变化等）
    for (const item of matchInfo) {
      const matchData = (JSON.parse(matches.find((m) => m.matchId === item.matchId)?.matchData as string) as MatchData) || {};

      // 获取赔率变化
      const oddsHistory = await this.dataService.getOddsHistory(item.matchId);
      // item.oddsHistory = oddsHistory;

      // 获取历史比赛数据
      const homeTeamId = matchData.homeTeam?.id;
      const awayTeamId = matchData.awayTeam?.id;

      if (homeTeamId && awayTeamId) {
        const homeHistory1 = await this.dataService.getTeamHistoryMatches(homeTeamId);
        const awayHistory1 = await this.dataService.getTeamHistoryMatches(awayTeamId);
        const homeHistory2 = await this.dataService.getTeamHistoryMatches(homeTeamId, 'home');
        const awayHistory2 = await this.dataService.getTeamHistoryMatches(awayTeamId, 'away');

        // 获取积分榜数据
        const rankingData = await this.dataService.getTeamRanking(item.matchId);

        // 组装历史数据
        item.historyData = {
          homeTeamRecent10: homeHistory1,
          awayTeamRecent10: awayHistory1,
          homeTeamRecent6Home: homeHistory2,
          awayTeamRecent6Away: awayHistory2,
        };
        item.rankingData = rankingData;
      }
    }

    // 4 只收集数据(测试使用)
    if (collection) return console.log('收集完成');

    // 5 调用大模型
    this.logService.info(`${dayjs(date[0]).format('YYYY-MM-DD')} ~ ${dayjs(date[1]).format('YYYY-MM-DD')} 开始 ${aiModel} 自动投注计划`);
    const excuteMethod = { DeepSeek: 'excuteDeepSeek', Doubao: 'excuteDoubao', Qwen: 'excuteQwen' };
    const response = (await this.openaiService[excuteMethod[aiModel]]<AIBettings>([
      ...getAiRecommendPrompt(historyBets),
      {
        role: 'user',
        content: `当天可选比赛分析数据：${JSON.stringify(matchInfo)}`,
      },
    ])) as AIBettings;

    // 6 存储数据
    if (response) {
      await this.redisService.lpush(
        CACHE_KEY,
        JSON.stringify({
          date: dayjs(date[0]).format('YYYY-MM-DD'),
          profit: 0,
          bets: Array.isArray(response) ? this.formatResponse(response, matchInfo) : [],
        }),
      );
      const str = response
        .map((item, itemIndex) => {
          const content = `第${itemIndex + 1}个投注组合：投注类型：${item.betType}，最高赔率：${item.highOdds}，最低赔率：${item.lowOdds}`;
          const matchContent = `${item.matches.map((match) => `${match.matchNum}-${match.prediction.map((pr) => PredictionMap[pr] || '-').join('/')}`).join('+')}`;
          return `${content}，比赛组合为：${matchContent}`;
        })
        .join('\n');
      this.logService.info(`✨ ${aiModel} 大模型调用完成`);
    }

    this.logService.info(`${dayjs(date[0]).format('YYYY-MM-DD')} ~ ${dayjs(date[1]).format('YYYY-MM-DD')} ${aiModel} 自动投注计划完成`);
  }
  formatResponse(response: AIBettings, matchInfo: any[]) {
    response.forEach((item) => {
      item.matches.forEach((match) => {
        // 存储对应的分析数据
        const data = matchInfo.find((item) => item.matchId === +match.matchId);
        if (data) match.useAnalysisData = data;
      });
    });
    return response;
  }

  // 2) AI 分析结果解析
  async getAIBetPlanMatchResult(aiModel: 'DeepSeek' | 'Doubao' | 'Qwen') {
    // 1 获取缓存数据
    const CACHE_KEY = `AI_BET_PLAN:${aiModel}`;
    const cacheHistoryBets = await this.redisService.lrange(CACHE_KEY, 0, -1);
    const historyBets = cacheHistoryBets.slice(0, 30).map((item) => JSON.parse(item));
    if (!historyBets.length) return;

    // 输出 historyBets 到 txt 文件
    const outputDir = path.join(process.cwd(), 'output');
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }
    const filename = `historyBets_${aiModel}_${dayjs().format('YYYY-MM-DD')}.txt`;
    const filepath = path.join(outputDir, filename);
    fs.writeFileSync(filepath, JSON.stringify(historyBets, null, 2), 'utf-8');
    this.logService.info(`historyBets 已输出到文件: ${filepath}`);

    // 2 获取比赛结果
    for (const bteIndex in historyBets) {
      const betItem = historyBets[bteIndex];
      if (!Array.isArray(betItem.bets)) continue;
      // 查询匹配比赛结果
      const matchIds = betItem.bets.flatMap((bet) => bet.matches.map((match) => +match.matchId)) || [];
      const matches = await this.prismaService.match.findMany({
        where: { matchId: { in: matchIds } },
        select: { matchId: true, status: true, handicap: true, fullScore: true },
      });
      // 判断结果是否正确
      let amount = 0;
      betItem.bets.forEach((bet) => {
        bet.matches.forEach((betMatch) => {
          const matchId = betMatch.matchId;
          const matchResult = betMatch.prediction.map((item) => StatusPredictionMap[item]);
          const matchData = matches.find((item) => item.matchId === matchId);
          betMatch.isCorrect = matchResult.includes(matchData?.status) || matchResult.includes(matchData?.handicap);
          betMatch.odd = betMatch.odds[matchResult.findIndex((t) => t === matchData?.status || t === matchData?.handicap)] || 0;
        });
        // 判断比赛结果都对, 设置金额
        if (bet.matches.every((item) => item.isCorrect)) {
          const matchOdd = bet.matches.reduce((acc, item) => acc * item.odd, 1).toFixed(2);
          const bonus = (process.env.AI_BET_AMOUNT * matchOdd).toFixed(2);
          const matchCount = bet.matches.flatMap((item) => item.prediction.length).reduce((acc, item) => acc * item, 1);
          console.log(matchCount);

          amount = +bonus / matchCount - process.env.AI_BET_AMOUNT;
        } else {
          amount = -process.env.AI_BET_AMOUNT;
        }
      });
      // 回填结果
      betItem.profit = amount;
      await this.redisService.lset(CACHE_KEY, +bteIndex, JSON.stringify(historyBets[bteIndex]));
    }

    // 3 输出战绩
    this.outputResult(aiModel, historyBets);
  }
  async outputResult(aiModel: 'DeepSeek' | 'Doubao' | 'Qwen', historyBets: any[]) {
    let totalProfit = 0; // 总盈亏
    let totalBets = 0; // 总投注组合数
    let winBets = 0; // 全部正确的投注组合数
    let twoStringOneOneCorrect = 0; // 二串一两场对一场次数
    let twoStringOneAllWrong = 0; // 二串一两场全错次数

    historyBets.forEach((betItem) => {
      if (!Array.isArray(betItem.bets) || betItem.bets.length === 0) return;

      totalProfit += betItem.profit || 0;

      betItem.bets.forEach((bet) => {
        if (!Array.isArray(bet.matches)) return;

        totalBets++;

        // 判断是否全部正确
        const allCorrect = bet.matches.every((match) => match.isCorrect === true);
        if (allCorrect) {
          winBets++;
        }

        // 统计二串一的情况
        if (bet.matches.length === 2) {
          const correctCount = bet.matches.filter((match) => match.isCorrect === true).length;
          if (correctCount === 1) {
            twoStringOneOneCorrect++;
          } else if (correctCount === 0) {
            twoStringOneAllWrong++;
          }
        }
      });
    });

    // 计算胜率
    const winRate = totalBets > 0 ? ((winBets / totalBets) * 100).toFixed(2) : '0.00';

    // 输出战绩
    this.logService.info(`========== ${aiModel} 投注战绩统计 ==========`);
    this.logService.info(`总投注组合数：${totalBets}`);
    this.logService.info(`胜率：${winRate}%`);
    this.logService.info(`总盈亏：${totalProfit.toFixed(2)}元`);
    this.logService.info(`二串一两场对一场次数：${twoStringOneOneCorrect}`);
    this.logService.info(`二串一两场全错次数：${twoStringOneAllWrong}`);
    this.logService.info(`==========================================`);
  }

  // 3) AI 测试分析
  async aiTestAnalyz(aiModel: 'DeepSeek' | 'Doubao' | 'Qwen' = 'DeepSeek') {
    const testMonth = '2025-10-31';
    const fns: any = [];
    for (let i = 0; i < 4; i++) {
      const todayam = dayjs(testMonth).add(i, 'day').toDate();
      const tomorrowam = dayjs(testMonth)
        .add(i + 1, 'day')
        .startOf('day')
        .add(+process.env.PLAN_TIME_RANGE + 2, 'hour')
        .toDate();
      fns.push(() => this.aiBetAnalyz(aiModel, [todayam, tomorrowam]));
    }
    executeBatches(fns, 4);
  }
}
